package com.codeberry.yws;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

public class Request {
  private Map<String, Object> args;
  private String fullPath;

  public Request(BufferedReader reader) throws IOException {
    args = new HashMap<String, Object>();
    String fullPath = "/";
    String line = readLineLimited(reader, 1024);

    System.out.println("line = " + line);
    StringTokenizer tok = new StringTokenizer(line);
    boolean isPost = false;
    while (tok.hasMoreTokens()) {
      String token = tok.nextToken();
      if ("GET".equalsIgnoreCase(token) ||
          "POST".equalsIgnoreCase(token)) {
        isPost = "POST".equalsIgnoreCase(token);
        break;
      }
    }
    if (tok.hasMoreTokens()) {
      fullPath = tok.nextToken();
    }

    fullPath = fullPath.replace('\\', '/');
    fullPath = leftTrimSlash(fullPath);

    int contentLength = skipHeadersAndGetContentLength(reader);

    if (isPost) {
      char[] buf = new char[contentLength];
      int off = 0;
      while ((off += reader.read(buf, off, buf.length - off)) < buf.length) {
      }
      parseQueryString(new String(buf));
    }

    int paramIndex;
    if ((paramIndex = fullPath.indexOf('?')) >= 0) {
      String argLine = fullPath.substring(paramIndex + 1);
      fullPath = fullPath.substring(0, paramIndex);
      parseQueryString(argLine);
    }

    this.fullPath = fullPath;
  }

  private int skipHeadersAndGetContentLength(BufferedReader reader) throws IOException {
    int contentLength = 0;
    String tmp;
    while ((tmp = reader.readLine()) != null &&
           !tmp.isEmpty()) {
      //...skipping all headers
      System.out.println("tmp = " + tmp);
      tmp = tmp.trim().toLowerCase();
      if (tmp.startsWith("content-length:")) {
        contentLength = Integer.parseInt(tmp.substring(15).trim());
      }
    }
    return contentLength;
  }

  private String readLineLimited(BufferedReader reader, int lengthLimit) throws IOException {
    StringBuilder buf = new StringBuilder(lengthLimit);
    int readChar;
    reader.mark(1);
    while ((readChar = reader.read()) != -1) {
      if ('\r' == readChar ||
          '\n' == readChar) {
        break;
      }
      if (buf.length() >= buf.capacity()) {
        throw new IOException("request line too long: maxLength=" + buf.capacity());
      }
      reader.mark(1);
      buf.append((char) readChar);
    }
    if (reader.read() != '\n') {
      reader.reset();
    }
    return buf.toString();
  }

  private void parseQueryString(String postData) throws UnsupportedEncodingException {
    System.out.println(postData);
    String[] argsStr = postData.split("&");
    for (String arg : argsStr) {
      String[] entry = arg.split("=");
      String key = URLDecoder.decode(entry[0], "utf-8");
      String value = URLDecoder.decode(entry[1], "utf-8");
      this.args.put(key, value);
    }
    System.out.println("args = " + args);
  }

  private String leftTrimSlash(String ret) {
    while (ret.startsWith("/")) {
      ret = ret.substring(1);
    }
    return ret;
  }

  public String getFullPath() {
    return fullPath;
  }

  public Map<String, Object> getArgs() {
    return args;
  }

  public String getTranslatedPath(ContextHandler handler) {
    String contextPath = handler.getContextPath();
    if (fullPath.startsWith(contextPath)) {
      return fullPath.substring(contextPath.length());
    }

    throw new IllegalArgumentException("full path does not match context path");
  }
}
